package org.example;

import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javassist.*;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

// Java Agent主类
public class PerformanceAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Java Agent 启动成功!");
        inst.addTransformer(new PerformanceTransformer());
    }

    // 字节码转换器
    static class PerformanceTransformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                ProtectionDomain protectionDomain, byte[] classfileBuffer) {
//            System.out.println("进入转换");
//            System.out.println("className:"+className);
            // 只处理我们感兴趣的类
            if (!className.startsWith("com/example")) {
                return classfileBuffer;
            }

            try {
                System.out.println("className:" + className);
                System.out.println("protectionDomain:" + protectionDomain);
                ClassPool cp = ClassPool.getDefault();
                if (loader != null) {
                    cp.insertClassPath(new LoaderClassPath(loader));
                }
                System.out.println("1111:");
                CtClass ctClass = cp.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
                System.out.println("Successfully made CtClass for: " + className);

                CtBehavior[] methods = ctClass.getDeclaredBehaviors(); // 获取所有方法


                // 遍历所有方法
                for (CtMethod method : ctClass.getDeclaredMethods()) {
//                    Object params = method.get();
                    MethodInfo methodInfo = method.getMethodInfo();
                    // 不处理构造方法
                    if (method.getName().equals("<init>") || method.getName().equals("<clinit>")) {
                        continue;
                    }
                    // 方法：入参信息
                    CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
                    // 获取局部变量表信息（位置1就是第一次参数，位置2就是第二个参数，以此类推。。。）
                    LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
                    method.insertBefore("System.out.println(\"attr：" + attr + "\");");
                    CtClass[] parameterTypes = method.getParameterTypes();

                    // 获取局部变量表的长度
                    boolean isStatic = (methodInfo.getAccessFlags() & AccessFlag.STATIC) != 0;  // 判断是否为静态方法
                    int parameterSize = isStatic ? attr.tableLength() : attr.tableLength() - 1; // 静态类型取值
                    // 参数的名称
                    List<String> parameterNameList = new ArrayList<>(parameterSize);
                    // 参数的类型
                    List<String> parameterTypeList = new ArrayList<>(parameterSize);
                    // 参数值
                    StringBuilder parameters = new StringBuilder();
                    for (int i = 0; i < parameterSize; i++) {
                        // 非静态类型去掉第一个this参数
                        method.insertBefore("System.out.println(\"parameterSize：" + parameterSize + "\");");
                        parameterNameList.add(attr.variableName(i + (isStatic ? 0 : 1)));
                        parameterTypeList.add(parameterTypes[i].getName());
                        if (i + 1 == parameterSize) {
                            parameters.append("$").append(i + 1);
                        } else {
                            parameters.append("$").append(i + 1).append(",");
                        }
                    }
//                    method.insertBefore("System.out.println(\"参数列表：" + parameters + "\");");

//                     方法：出参信息
                    CtClass returnType = method.getReturnType();
                    String returnTypeName = returnType.getName();
                    String parameterNameListValue = parameterNameList.toString();
                    String parameterTypeListValue = parameterTypeList.toString();
                    method.addLocalVariable("parametersValue", cp.get(String.class.getName()));
//                    method.insertBefore("parametersValue=\"\";parametersValue+=$1.getQueryString();parametersValue+=\",\";parametersValue+=$1.getStatus(); System.out.println(\"参数的名称：" + parameterNameListValue + ", 参数的类型：" + parameterTypeListValue + ", 参数的值\"+parametersValue+\";\");");
                    method.insertBefore("parametersValue=\"\";parametersValue+=$1.getQueryString(); System.out.println(\"参数的名称：" + parameterNameListValue + ", 参数的类型：" + parameterTypeListValue + ", 参数的值\"+parametersValue+\";\");");
                    method.insertBefore("System.out.println(\"返回值类型：" + returnTypeName + "\");");


                    // 插入性能监控代码
                    method.addLocalVariable("_startTime", CtClass.longType);
                    method.insertBefore("_startTime = System.currentTimeMillis();");

                    String methodName = method.getLongName();
                    method.insertAfter(
                            "System.out.println(\"方法 " + methodName + " 执行时间: \" + " +
                                    "(System.currentTimeMillis() - _startTime) + \"ms\");"
                    );
                }

                return ctClass.toBytecode();
            } catch (Exception e) {
                System.out.println("ERROR");
                e.printStackTrace();
            }

            return classfileBuffer;
        }
    }
}